package com.wisdom.system.api.core;

import com.alibaba.fastjson.JSON;
import com.wisdom.system.entity.base.PageResult;
import com.wisdom.system.entity.out.ResultBody;
import com.wisdom.system.common.annotation.SerializedField;
import com.wisdom.system.common.encryption.DesHelper;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.lang.reflect.Field;
import java.util.*;

@Order(1)
@ControllerAdvice(basePackages = "com.wisdom.system.api.controller")
public class MIResponseBody implements ResponseBodyAdvice {

    private String moduleName = null;
    //包含项
    private String[] includes = {};
    //排除项
    private String[] excludes = {};
    //是否加密
    private boolean encode = false;
    private boolean outResultBody = true;

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object obj, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        //重新初始化为默认值
        includes = new String[]{};
        excludes = new String[]{};
        encode = false;
        outResultBody = true;
        if (obj == null) {
            return null;
        }
        if (Objects.requireNonNull(methodParameter.getMethod()).isAnnotationPresent(SerializedField.class)) {
            //获取注解配置的包含和去除字段
            SerializedField serializedField = methodParameter.getMethodAnnotation(SerializedField.class);
            assert serializedField != null;
            moduleName = serializedField.moduleName();
            includes = serializedField.includes();
            excludes = serializedField.excludes();
            //是否加密
            encode = serializedField.encode();
            //是否处理输出ResultBody
            outResultBody = serializedField.outResultBody();
            Object retResult;
            if (excludes.length > 0 || includes.length > 0) {
                if (obj.getClass().getName().equals("PageResult")) {
                    List list = ((PageResult) obj).getList();
                    Long total = ((PageResult) obj).getTotal();
                    list = handleList(list);
                    retResult = new PageResult(list, total);
                } else if (obj instanceof List) {
                    List list = (List) obj;
                    retResult = handleList(list);
                } else {
                    retResult = handleSingleObject(obj);
                }
            } else {
                retResult = obj;
            }
            if (outResultBody) {
                ResultBody resultBody;
                resultBody = new ResultBody(retResult);
                resultBody.setMsg(moduleName + "成功!");
                // 当返回值为String类型时，直接返回实体会报错，改为返回字符串
                if (retResult.getClass().getName().equals("java.lang.String")) {
                    return JSON.toJSONString(resultBody);
                }
                return resultBody;
            } else {
                return retResult;
            }
        }
        return obj;
    }

    /**
     * 处理返回值是单个enity对象
     *
     * @param o
     * @return
     */
    private Object handleSingleObject(Object o) {
        Map<String, Object> map = new HashMap<String, Object>();
        //获取本身包含继承的父类
        Class clazz = o.getClass();
        List<Field> fields = new ArrayList<Field>();
        while (clazz != null) {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
            clazz = clazz.getSuperclass();
        }
        for (Field field : fields) {
            if (includes.length > 0) {
                //有限考虑包含字段
                if (DesHelper.isStringInArray(field.getName(), includes)) {
                    Object newVal = getNewValue(o, field);
                    map.put(field.getName(), newVal);
                }
            } else {
                //去除字段
                if (excludes.length > 0) {
                    if (!DesHelper.isStringInArray(field.getName(), excludes)) {
                        Object newVal = getNewValue(o, field);
                        map.put(field.getName(), newVal);
                    }
                }
            }
        }
        return map;
    }

    /**
     * 处理返回值是列表
     *
     * @param list
     * @return
     */
    private List handleList(List list) {
        List retList = new ArrayList();
        for (Object o : list) {
            Map map = (Map) handleSingleObject(o);
            retList.add(map);
        }
        return retList;
    }

    /**
     * 获取加密后的新值
     *
     * @param o
     * @param field
     * @return
     */
    private Object getNewValue(Object o, Field field) {
        Object newVal = null;
        try {
            field.setAccessible(true);
            Object val = field.get(o);
            if (val != null) {
                if (encode) {
                    newVal = DesHelper.encode(val.toString());
                } else {
                    newVal = val;
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return newVal;
    }

}
